﻿//Copyright (C) 2009  Jaco (ScionBot.com)

//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.

//You should have received a copy of the GNU General Public License
//along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Scion.Library.Underlying;
using Scion.Library.Antiban;
using Scion.Library.RS.UI;

namespace Scion.Library.RS
{
    /// <summary>
    /// A RSObject is anything that can be "animated" upon.
    /// </summary>
    public class RSObject
    {
        Superior super;
        Color objectColour;
        string topText;
        BufferedImage objectImage;
        Rectangle searchBounds;
        int tolerance;
        int maxValue;
        Point spiralPoint;
        bool masked;
        Color[] topTextColour;

        /// <summary>
        /// An object that is to be found with basic colour searching.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="objectCol">The colour of the object.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="sBounds">The bounds to search the object in.</param>
        /// <param name="tol">The tolerance of the colour.</param>
        /// <param name="maxV">The maximum value to use as a clicking offset (antiban).</param>
        public RSObject(Superior s, Color objectCol, string tText, Rectangle sBounds, int tol, int maxV)
        {
            super = s;
            topTextColour = TopText.Common;
            objectColour = objectCol;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            maxValue = maxV;
        }

        /// <summary>
        /// An object that is to be found with basic colour searching.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="objectCol">The colour of the object.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="tTextCol">The colour of the top text.</param>
        /// <param name="sBounds">The bounds to search the object in.</param>
        /// <param name="tol">The tolerance of the colour.</param>
        /// <param name="maxV">The maximum value to use as a clicking offset (antiban).</param>
        public RSObject(Superior s, Color objectCol, string tText, Color[] tTextCol, Rectangle sBounds, int tol, int maxV)
        {
            super = s;
            topTextColour = tTextCol;
            objectColour = objectCol;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            maxValue = maxV;
        }

        /// <summary>
        /// An object that is to be found with the spiral colour finding function.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="spiralP">The origin of the search.</param>
        /// <param name="objectCol">The colour of the object.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="sBounds">The search bounds to find the colour in.</param>
        /// <param name="tol">The tolerance of the colour.</param>
        /// <param name="maxV">The maximum value to use as a clicking offset (antiban).</param>
        public RSObject(Superior s, Point spiralP, Color objectCol, string tText, Rectangle sBounds, int tol, int maxV)
        {
            super = s;
            topTextColour = TopText.Common;
            objectColour = objectCol;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            maxValue = maxV;
            spiralPoint = spiralP;
        }

        /// <summary>
        /// An object that is to be found with the spiral colour finding function.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="spiralP">The origin of the search.</param>
        /// <param name="objectCol">The colour of the object.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="tTextCol">The colour of the top text.</param>
        /// <param name="sBounds">The search bounds to find the colour in.</param>
        /// <param name="tol">The tolerance of the colour.</param>
        /// <param name="maxV">The maximum value to use as a clicking offset (antiban).</param>
        public RSObject(Superior s, Point spiralP, Color objectCol, string tText, Color[] tTextCol, Rectangle sBounds, int tol, int maxV)
        {
            super = s;
            topTextColour = tTextCol;
            objectColour = objectCol;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            maxValue = maxV;
            spiralPoint = spiralP;
        }

        /// <summary>
        /// An object that is to be found with the find bitmap function.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="objectBmp">The bitmap of the object.</param>
        /// <param name="mask">If the bitmap is a mask or not.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="sBounds">The search bounds to find the bitmap in.</param>
        /// <param name="tol">The tolerance to use to find the bitmap.</param>
        public RSObject(Superior s, BufferedImage objectBmp, bool mask, string tText, Rectangle sBounds, int tol)
        {
            super = s;
            topTextColour = TopText.Common;
            objectImage = objectBmp;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            masked = mask;
        }

        /// <summary>
        /// An object that is to be found with the find bitmap function.
        /// </summary>
        /// <param name="s">The bot's instance.</param>
        /// <param name="objectBmp">The bitmap of the object.</param>
        /// <param name="mask">If the bitmap is a mask or not.</param>
        /// <param name="tText">The top text of the object.</param>
        /// <param name="tTextCol">The colour of the top text.</param>
        /// <param name="sBounds">The search bounds to find the bitmap in.</param>
        /// <param name="tol">The tolerance to use to find the bitmap.</param>
        public RSObject(Superior s, BufferedImage objectBmp, bool mask, string tText, Color[] tTextCol, Rectangle sBounds, int tol)
        {
            super = s;
            topTextColour = tTextCol;
            objectImage = objectBmp;
            topText = tText;
            searchBounds = sBounds;
            tolerance = tol;
            masked = mask;
        }

        /// <summary>
        /// Executes an action on the object.
        /// </summary>
        /// <param name="action">The action to perform (choose option). Leave null or empty if you just want to click on the object.</param>
        /// <param name="textColour">The text colour.</param>
        /// <returns>Returns true if the function succeeded.</returns>
        public bool DoAction(string action, Color[] textColour)
        {
            List<Point> points = null;
            if (spiralPoint == null && objectImage == null)
                points = Cluster.FindColour(super.Canvas.GetCanvas(0, false), searchBounds, objectColour, tolerance);
            else if (spiralPoint != null && objectImage == null)
                points = Cluster.FindColourSpiral(super.Canvas.GetCanvas(0, false), searchBounds, spiralPoint, objectColour, tolerance);
            else if (objectImage != null)
                points = Cluster.FindBitmap(super.Canvas.GetCanvas(0, false), objectImage, searchBounds, masked, tolerance);
            if (points == null)
                return false;
            TopText tt = new TopText(super);
            foreach (Point p in points)
            {
                if (objectImage != null)
                {
                    SizeRandom rnd = new SizeRandom(new Size(objectImage.imageWidth, objectImage.imageHeight), new Point(p.X, p.Y));
                    super.Mouse.MoveMouse(new PointRandom(rnd.random.X, rnd.random.Y, 0));
                }
                else
                    super.Mouse.MoveMouse(new PointRandom(p.X, p.Y, maxValue));
                super.Sleep(new SleepRandom(50, 100));
                if (tt.FindText(topTextColour, topText, TopText.Tolerance))
                {
                    if (action != "")
                    {
                        super.Mouse.ClickMouse(new PointRandom(super.Mouse.CurrentX, super.Mouse.CurrentY, 0), false);
                        super.Sleep(new SleepRandom(200, 300));
                        ChooseOption co = new ChooseOption(super);
                        bool result = co.DoAction(textColour, action);
                        if (result)
                        {
                            WaitForAction();
                            return true;
                        }
                        else
                        {
                            co.DoAction(ChooseOption.Common, "Cancel");
                            super.Sleep(new SleepRandom(300, 400));
                        }
                    }
                    else
                    {
                        super.Mouse.ClickMouse(new PointRandom(super.Mouse.CurrentX, super.Mouse.CurrentY, 0), true);
                        WaitForAction();
                        return true;
                    }
                }
            }
            return false;
        }

        private void WaitForAction()
        {
            int failSafe = 0;
            //If the character is animating or is moving, we know that our current character is processing the action.
            //If we're still in the loop for about 5 seconds, our action failed. Therefore, we break the loop and fall through the script.
            while (true)
            {
                if (super.IsAnimating() || super.IsMoving())
                    break;
                else if (failSafe > 15)
                    break;
                super.Sleep(new SleepRandom(300, 400));
                failSafe++;
            }
            //Wait until the character is not moving anymore.
            while (super.IsMoving())
                super.Sleep(new SleepRandom(300, 400));
        }
    }
}
